package com.example.security.config;

import com.example.security.component.MySecurityFilter;
import com.example.security.filter.MyAuthenticationFilter;
import com.example.security.handle.MyAuthenticationFailureHandler;
import com.example.security.handle.MyAuthenticationSuccessHandler;
import com.example.security.handle.MyLogoutSuccessHandler;
import com.example.security.handle.MySessionInformationExpiredStrategy;
import com.example.security.service.UserInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.annotation.Resource;


/**
 * @author LiYuhang
 * @version 0.1
 * @application
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);


    /**
     * session仓库
     */
    @Autowired
    FindByIndexNameSessionRepository sessionRepository;

    /**
     * spring-Session注册回调中心
     */
    @Autowired
    private SpringSessionBackedSessionRegistry sessionRegistry;

    /**
     * Spring-session
     *
     * @return
     */
    @Bean
    SpringSessionBackedSessionRegistry sessionRegistry() {
        sessionRegistry = new SpringSessionBackedSessionRegistry(sessionRepository);
        return new SpringSessionBackedSessionRegistry(sessionRepository);
    }


    /**
     * userInfro
     */
    @Resource
    UserInfoService userInfoService;

    /**
     * redisTemplate
     */
    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 自定义过滤器，拦截用户权限
     */
    @Autowired
    MySecurityFilter myFilter;




    /**
     * 加密器
     *
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     * 配置UserDetailService 实现类
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userInfoService);
    }

    /**
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                /****对于获取token的rest api要允许匿名访问*/
                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
                .and().formLogin().permitAll()
                .and().logout().logoutUrl("/logout")
                .and().logout().logoutSuccessHandler(new MyLogoutSuccessHandler(sessionRegistry))
                .and().csrf().disable()
                .sessionManagement()
                //session并发访问限制
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true)
                //spring session
                .sessionRegistry(sessionRegistry);
        //处理强制下线
        http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry,new MySessionInformationExpiredStrategy()),ConcurrentSessionFilter.class);
        //处理正常登录
        http.addFilterAt(myAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
        // 禁用缓存
        http.headers().cacheControl();
    }

    @Bean
    MyAuthenticationFilter myAuthenticationFilter() throws Exception {
        MyAuthenticationFilter filter = new MyAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
        filter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
        filter.setAuthenticationManager(authenticationManagerBean());
        ConcurrentSessionControlAuthenticationStrategy sessionStrategy =
                new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
        sessionStrategy.setMaximumSessions(1);
        filter.setSessionAuthenticationStrategy(sessionStrategy);

        return filter;
    }


}
